#include "indexer.h"
#include "file_func.h"
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <sstream>

unsigned long file_index = 0;
unsigned long files_added = 0;
unsigned long files_updated = 0;

bool is_loaded = 0;
Atree* fileToIndexTree = new Atree();
Atree* indexToFileTree = new Atree();
Atree* modifiedTree = new Atree();
Atree* fullTextIndexTree = new Atree();

char* getIndexChar(char* filename)
{
  fileToIndexTree->lookupData(filename, false, true);
  return fileToIndexTree->returnData();
}
unsigned long getIndex(char* filename)
{
  fileToIndexTree->lookupData(filename, false, false);
  unsigned long tmpResult;
  char* tmpIndex = fileToIndexTree->returnData();
  tmpResult = std::atol(tmpIndex);
  delete[] tmpIndex;
  return tmpResult;
}

char* intToChar(int t)
{
  std::stringstream ins;
  ins << t;
  char* nc = new char[std::strlen(ins.str().c_str()) + 1];
  std::strcpy(nc,ins.str().c_str());
  return nc;
}
char* getFileName(char* index)
{
  indexToFileTree->lookupData(index, false, false);
  return indexToFileTree->returnData();
}
void index_directory(char* directory)
{
  char* maxIndexFile = dirCombine(directory, ".max_index.dat");

  if (doesFileExist(maxIndexFile))
  {
    if (!is_loaded)
    {
      load_indices(directory);
    }
    std::ifstream maxInputStream(maxIndexFile);
    maxInputStream >> file_index;
    maxInputStream.close();
  }
  else
  {
    file_index = 0;
  }

  files_added = 0;
  files_updated = 0;

  recursive_index(directory);

  std::cout << "Files Added " << files_added << std::endl;
  std::cout << "Files Updated " << files_updated << std::endl;
  std::cout << "Files Indexed Total " << file_index << std::endl;
  std::ofstream maxOutputStream(maxIndexFile);
  maxOutputStream << file_index;
  maxOutputStream.close();

  char* fileToIndexTreeFile = dirCombine(directory,".file_to_index.atree");
  char* indexToFileTreeFile = dirCombine(directory,".index_to_file.atree");
  char* modifiedTreeFile = dirCombine(directory, ".modified_index.atree");
  char* fullTextIndexTreeFile = dirCombine(directory, ".full_text_index.atree");

  fileToIndexTree->saveData(fileToIndexTreeFile);
  indexToFileTree->saveData(indexToFileTreeFile);
  modifiedTree->saveData(modifiedTreeFile);
  fullTextIndexTree->saveData(fullTextIndexTreeFile);
}
void recursive_index(char* directory)
{
  int item_count;
  char** items = getDirectoryListing(directory, item_count);

  for (int i = 0; i < item_count; i++)
  {
    fileToIndexTree->lookupData(items[i], false, true);

    bool bChangedFlag = false, bNewFlag = false;
    
    char* indexChar;
    
    if (!fileToIndexTree->hasData())
    {
      bChangedFlag = true;
      bNewFlag = true;
    }
    else
    {
      int lastModified = 0;
      
      while (fileToIndexTree->hasData())
      {
        char* tmp = fileToIndexTree->returnData();
        delete[] tmp;
        fileToIndexTree->moveNextData();
      }
      indexChar = getIndexChar(items[i]);
      modifiedTree->lookupData(indexChar, false, false);
      while (modifiedTree->hasData())
      { 
        char* tmp = modifiedTree->returnData();
        lastModified = std::atoi(tmp);
        delete[] tmp;
        modifiedTree->moveNextData();
      }
      if (lastModified != getModifiedDate(items[i]))
      {
        bChangedFlag = true; 
      }
    }

    if (bChangedFlag)
    {
      if (bNewFlag)
      {
        //If we have a new file, index it
        std::stringstream ins;
        ins << file_index;
        char* strIndex = new char[std::strlen(ins.str().c_str()) + 1];
        std::strcpy(strIndex, ins.str().c_str());

        fileToIndexTree->insertData(items[i], strIndex, true);
        indexToFileTree->insertData(strIndex, items[i], false);
      
        delete[] strIndex;

        indexChar = getIndexChar(items[i]);

        file_index++;
        files_added++;
      }

      //Record last modification date of file, so we don't read it till it changes
      files_updated++;
      char* iChar = intToChar(getModifiedDate(items[i]));
      modifiedTree->insertData(indexChar, iChar, false);
      delete[] iChar;
      
      //Read our files contents if it is not a binary file
      if (isDirectory(items[i]))
      {
        recursive_index(items[i]);
      }
      else if (isRegular(items[i]) && !isBinary(items[i]))
      {
        std::cout << "LOADING: " << items[i] << std::endl;

        std::ifstream fReader(items[i]);
        std::string word;
        while (fReader >> word)
        {
          fullTextIndexTree->insertData(word.c_str(), indexChar, true);
        }
        fReader.close();
      }

      delete[] indexChar;
    }
  }
}
void load_indices(char* directory)
{
  char* fileToIndexTreeFile = dirCombine(directory,".file_to_index.atree");
  char* indexToFileTreeFile = dirCombine(directory,".index_to_file.atree");
  char* modifiedTreeFile = dirCombine(directory, ".modified_index.atree");
  char* fullTextIndexTreeFile = dirCombine(directory, ".full_text_index.atree");

  fileToIndexTree->loadData(fileToIndexTreeFile);
  indexToFileTree->loadData(indexToFileTreeFile);
  modifiedTree->loadData(modifiedTreeFile);
  fullTextIndexTree->loadData(fullTextIndexTreeFile);

  is_loaded = 1;
}
void perform_search(char* searchText)
{
  fullTextIndexTree->lookupData(searchText, true, true);
  while (fullTextIndexTree->hasData())
  {
    char* tmp = fullTextIndexTree->returnData();
    char* file = getFileName(tmp);
    
    std::cout << file << std::endl;
    
    delete[] file;
    delete[] tmp;
    fullTextIndexTree->moveNextData();
  }
}
